package de.cms.kff.dao;

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import de.cms.kff.dto.MitarbeiterVerleihDTO;
import de.cms.kff.dto.VerleihDTO;
import de.cms.kff.model.Auto;
import de.cms.kff.model.Verleih;
import de.cms.kff.model.Mitarbeiter;

public class VerleihDao extends HibernateDaoSupport {
	SimpleDateFormat deutschesDatumsFormat = new SimpleDateFormat(
			"dd.MM.yyyy HH:mm");

	/**
	 * <p>
	 * returns all Verleih objects, which are not yet termiated.
	 * </p>
	 * <p>
	 * In order to access lazy loaded properties, a HibernateCallback is used.
	 * </p>
	 * 
	 * @return A sorted set of VerleihDTO objects
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Set<VerleihDTO> findNichtBeendetDTO() {
		HibernateTemplate template = getHibernateTemplate();
		return (Set<VerleihDTO>) template.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(Verleih.class);
				criteria.add(Restrictions.isNull("bis"));
				List<Verleih> alleVerleihe = criteria.list();
				return createDtoSet(alleVerleihe);
			}
		});
	}

	/**
	 * <p>
	 * returns all Verleih objects as MitarbeiterVerleihDTO objects.
	 * </p>
	 * <p>
	 * In order to access lazy loaded properties of those, a HibernateCallback
	 * is used.
	 * </p>
	 * 
	 * @return A sorted set of MitarbeiterVerleihDTO objects
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Set<VerleihDTO> findAllDTO() {
		HibernateTemplate template = getHibernateTemplate();
		return (Set<VerleihDTO>) template.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(Verleih.class);
				List<Verleih> alleVerleihe = criteria.list();
				return createDtoSet(alleVerleihe);
			}
		});
	}

	/**
	 * Private utility function.
	 * 
	 * @param verleihe
	 *            a List of persistent Verleih objects
	 * @return a Set of MitarbeiterVerleihDTO objects
	 */
	private Set<VerleihDTO> createDtoSet(List<Verleih> verleihe) {
		Set<VerleihDTO> results = new TreeSet<VerleihDTO>();
		for (Verleih f : verleihe) {
			Date bis = f.getBis();
			Date von = f.getVon();
			results.add(new VerleihDTO(f.getId(), f.getCreated(), f.getAuto()
					.getTyp(), f.getAuto().getKennzeichen(), (von == null ? ""
					: deutschesDatumsFormat.format(von)), (bis == null ? ""
					: deutschesDatumsFormat.format(bis)), f.getMitarbeiter()
					.getVorname(), f.getMitarbeiter().getNachname(), f
					.getKilometerstand()));

		}

		return results;
	}

	/**
	 * @return all Verleih objects in the database.
	 */
	@SuppressWarnings("unchecked")
	public List<Verleih> findAll() {
		HibernateTemplate template = getHibernateTemplate();
		@SuppressWarnings("rawtypes")
		List alleVerleihe = template.loadAll(Verleih.class);
		return (List<Verleih>) alleVerleihe;
	}

	/**
	 * Starts a trip specifying a Auto id and a set of Mitarbeiter ids.
	 * 
	 * @param autoId
	 * @throws DaoException
	 */
	public void verleihe(int autoId, int mitarbeiterId, int kilometerstand)
			throws DaoException {
		HibernateTemplate template = getHibernateTemplate();
		Auto a = (Auto) template.get(Auto.class, autoId);
		Mitarbeiter m = (Mitarbeiter) template.get(Mitarbeiter.class,
				mitarbeiterId);
		Verleih f = new Verleih();
		f.setCreated(new Date());
		f.setVon(new Date());
		f.setAuto(a);
		f.setMitarbeiter(m);
		f.setKilometerstand(kilometerstand);
		try {
			template.saveOrUpdate(f);
		} catch (DataAccessException e) {
			throw new DaoException(
					"Ein und der selbe Fahrer kann nicht zwei Verleihe durchführen.");
		}
	}

	/**
	 * Ends a trip by adding an ankunft date.
	 * 
	 * @param id
	 */
	public void rueckgeben(int id) {
		HibernateTemplate template = getHibernateTemplate();
		Verleih v = (Verleih) template.get(Verleih.class, id);
		v.setBis(new Date());
		template.saveOrUpdate(v);
	}

	@SuppressWarnings("unchecked")
	public Set<Verleih> findByAuto(Auto auto) {
		Session hibernateSession = getSession();
		Criteria crit = hibernateSession.createCriteria(Verleih.class);
		crit.add(Restrictions.eq("auto", auto));
		List<Verleih> tmp = crit.list();
		Set<Verleih> result = new HashSet<Verleih>();
		for (Verleih f : tmp) {
			result.add(f);
		}
		return result;
	}

}
